package admin

import (
	"log"
	"net/http"
	"sort"
	"time"

	"github.com/gin-gonic/gin"
	"gitee.com/laofa1/play/k_conf_mng/kconf_backend/models"
)

type OutUser struct {
	ID        uint64    `json:"id"`
	LoginName string    `json:"loginName"`
	Name      string    `json:"name"`
	Date      time.Time `json:"date"`
	Role      string    `json:"role"`
	IsEnabled bool      `json:"isEnabled"`
}

type CreateUserParam struct {
	LoginName string `json:"loginName" binding:"required"`
	UserName  string `json:"name" binding:"required"`
	Password  string `json:"password" binding:"required"`
	Role      string `json:"role" binding:"required"`
}

type DisableUserParam struct {
	ID uint64 `json:"id" binding:"required"`
}

type SetRoleParam struct {
	ID      uint64 `json:"id" binding:"required"`
	NewRole string `json:"newRole" binding:"required"`
}

type SetPasswordParam struct {
	ID          uint64 `json:"id" binding:"required"`
	NewPassword string `json:"newPassword" binding:"required"`
}

func GetUsers(c *gin.Context) {
	ownID := c.MustGet("userID").(uint64)
	users, err := models.GetAllUsers()
	if err != nil {
		log.Println(err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"status": "error",
			"data":   "fail to get all users",
		})
		return
	}
	var outUsers []OutUser
	for _, user := range users {
		// exclude user own
		if ownID != user.ID {
			outUsers = append(outUsers, OutUser{
				ID:        user.ID,
				LoginName: user.LoginName,
				Name:      user.UserName,
				Date:      user.CreatedAt,
				Role:      user.Role,
				IsEnabled: user.IsEnabled,
			})
		}
	}
	// sort
	sort.Slice(outUsers, func(i, j int) bool {
		return outUsers[i].ID < outUsers[j].ID
	})
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   outUsers,
	})
}

func CreateUser(c *gin.Context) {
	var userCreate CreateUserParam
	if err := c.BindJSON(&userCreate); err != nil {
		log.Println(err)
		return
	}

	switch userCreate.Role {
	case "admin":
		err := models.CreateAdmin(userCreate.LoginName, userCreate.UserName, userCreate.Password)
		if err != nil {
			log.Println(err)
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"data":   "error when trying to create user.",
			})
			return
		}
	case "user":
		err := models.CreateUser(userCreate.LoginName, userCreate.UserName, userCreate.Password)
		if err != nil {
			log.Println(err)
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"data":   "error when trying to create user.",
			})
			return
		}
	default:
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "fail",
			"data":   "role only accept user or admin.",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   "",
	})
}

func DisableUser(c *gin.Context) {
	var disableUserParam DisableUserParam
	if err := c.BindJSON(&disableUserParam); err != nil {
		log.Println(err)
		return
	}

	err := models.DisableUser(disableUserParam.ID)
	if err != nil {
		log.Println(err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"status": "error",
			"data":   "fail to disable user",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   "",
	})
	return
}

func EnableUser(c *gin.Context) {
	var disableUserParam DisableUserParam
	if err := c.BindJSON(&disableUserParam); err != nil {
		log.Println(err)
		return
	}

	err := models.EnableUser(disableUserParam.ID)
	if err != nil {
		log.Println(err)
		c.JSON(http.StatusInternalServerError, gin.H{
			"status": "error",
			"data":   "fail to enable user",
		})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   "",
	})
	return
}

func SetRole(c *gin.Context) {
	var setRoleParam SetRoleParam
	if err := c.BindJSON(&setRoleParam); err != nil {
		log.Println(err)
		return
	}

	switch setRoleParam.NewRole {
	case "admin":
		err := models.ChangeRole(setRoleParam.ID, "admin")
		if err != nil {
			log.Println(err)
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"data":   "fail to set user role to admin",
			})
			return
		}
	case "user":
		err := models.ChangeRole(setRoleParam.ID, "user")
		if err != nil {
			log.Println(err)
			c.JSON(http.StatusInternalServerError, gin.H{
				"status": "error",
				"data":   "fail to set user role to normal user",
			})
			return
		}
	default:
		log.Println("given role is error")
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "error",
			"data":   "given role is not correct",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   "",
	})
	return
}

// SetPassword is to reset password of user by admin
func SetPassword(c *gin.Context) {
	var setPasswordParam SetPasswordParam
	var err error
	if err = c.BindJSON(&setPasswordParam); err != nil {
		log.Println(err)
		return
	}

	err = models.SetPassword(setPasswordParam.ID, setPasswordParam.NewPassword)
	if err != nil {
		log.Println(err)
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "error",
			"data":   "error when try to reset password.",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data":   "",
	})
	return
}
